import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;

import cn.boodqian.airdata.*;

public class SaveBlob extends HttpServlet {
	private DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
	private final static Logger Log = Logger.getLogger(SaveBlob.class.getName());
	private String []airType = new String[]{"pm25","pm10","so2","no2", "co", "o3"};
	private static SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd_HHmmss");
	static {
	    fmt.setTimeZone(TimeZone.getTimeZone("GMT+8"));
	}

	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws IOException {
	    int hours = Integer.parseInt(req.getParameter("hour"));
	    
	    // This will update start/end date
		String str = getAirData( hours );
		
		String filename = fmt.format(new Date());
	    
		// Get a file service
		FileService fileService = FileServiceFactory.getFileService();

		// Create a new Blob file with mime-type "text/plain"
		AppEngineFile file = fileService.createNewBlobFile("application/zip", filename);

		// Open a channel to write to it
		boolean lock = true;
		FileWriteChannel writeChannel = fileService.openWriteChannel(file, lock);
		
		//convert as outputstream
		OutputStream blobOutputStream = Channels.newOutputStream(writeChannel);
		ZipOutputStream zip = new ZipOutputStream(blobOutputStream);                    
		zip.putNextEntry(new ZipEntry(filename+".txt"));
		zip.write(str.getBytes());
		zip.closeEntry();                    
		zip.close();

		// Now finalize
		writeChannel.closeFinally();

		// Now read from the file using the Blobstore API
		BlobKey blobKey = fileService.getBlobKey(file);
		res.getWriter().println("blob key: " + blobKey.getKeyString());
	}
	
	private String getAirData( int hours )
	{
	    ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String,String>>();

	    list.addAll(BeijingAirDataProvider.locationList);
	    list.addAll(ShanghaiAirDataProvider.locationList);
	    list.addAll(ShanghaiUSAirDataProvider.locationList);

	    ArrayList<HashMap<String, String>> cnemc_list = CNEMCAirDataProvider.getLocationList(null);
	    if( cnemc_list != null ) list.addAll(cnemc_list);
	    
	    ArrayList<String> idList = new ArrayList<String>();
	    for( HashMap<String, String> map : list ) {
	        String locId = map.get("id");
	        idList.add(locId);
	    }
	    
	    // These are what we present to client app so far, Shanghai location ids are out of date
	    // so need to put new Shanghai location ids as well
	    for( int i = 0; i < AirdataServlet.locationMappingData.length; i++ ) {
	        String locId = AirdataServlet.locationMappingData[i][1];
	    }

	    
	    StringBuilder sb = new StringBuilder();
	    for( String locId : idList ) {
	        String []a = locId.split("/");
	        if( a.length != 2 ) {
	            Log.severe(locId + " is not a valid location id");
	            continue;
	        }
	        String city = a[0];
	        String loc = a[1];
	        Log.info(String.format("Cleaning up for {%s, %s}", city, loc));
	        
	        Calendar cal = Calendar.getInstance();
	        //cal.add(Calendar.MONTH, -6); // Six months ago
	        //cal.set(Calendar.DAY_OF_MONTH, 1);
	        cal.set(2013, 2, 01, 0, 0);
	        Key parent = KeyFactory.createKey(AirDataProvider.kind, city);
	        Query query = new Query(AirDataProvider.kind, parent);
	        query.setFilter(
	                CompositeFilterOperator.and( 
	                        new FilterPredicate("time", Query.FilterOperator.LESS_THAN_OR_EQUAL, cal.getTime()),
	                        new FilterPredicate("location", Query.FilterOperator.EQUAL, loc)
	                        )
	                );
	        query.addSort("time",Query.SortDirection.DESCENDING);
	        PreparedQuery pq = datastoreService.prepare(query);

	        List<Entity> entityList = pq.asList(FetchOptions.Builder.withLimit( hours ));
	        Log.info("AirData List Size: " + entityList.size());
	        for(int i=0;i<entityList.size();i++) {
	            sb.append("location=");
	            sb.append(locId);
	            Entity e = entityList.get(i);
	            sb.append(",time=");
	            sb.append(fmt.format( (Date)e.getProperty("time") ));
	            for( String type : airType ) {
	                //e.g. "pm25=0.123"
	                sb.append(",");
	                sb.append(type);
	                sb.append("=");
	                sb.append( e.hasProperty(type) ?
	                        e.getProperty(type).toString()
	                        : "0");
	            }
	            sb.append("\n");
	            datastoreService.delete(e.getKey());
	        }
	    }
		return sb.toString();
	}
}
